/**
 * echarts组件：工具箱
 *
 * @desc echarts基于Canvas，纯Javascript图表库，提供直观，生动，可交互，可个性化定制的数据统计图表。
 * @author Kener (@Kener-林峰, kener.linfeng@gmail.com)
 *
 */


var Base = require('./base');
// 图形依赖
var LineShape = require('zrender/shape/Line');
var ImageShape = require('zrender/shape/Image');
var RectangleShape = require('zrender/shape/Rectangle');
var IconShape = require('../util/shape/Icon');
var ecConfig = require('../config');
ecConfig.toolbox = {
    zlevel: 0,
    // 一级层叠
    z: 6,
    // 二级层叠
    show: false,
    orient: 'horizontal',
    // 布局方式，默认为水平布局，可选为：
    // 'horizontal' ¦ 'vertical'
    x: 'right',
    // 水平安放位置，默认为全图右对齐，可选为：
    // 'center' ¦ 'left' ¦ 'right'
    // ¦ {number}（x坐标，单位px）
    y: 'top',
    // 垂直安放位置，默认为全图顶端，可选为：
    // 'top' ¦ 'bottom' ¦ 'center'
    // ¦ {number}（y坐标，单位px）
    color: [
        '#1e90ff',
        '#22bb22',
        '#4b0082',
        '#d2691e'
    ],
    disableColor: '#ddd',
    effectiveColor: 'red',
    backgroundColor: 'rgba(0,0,0,0)',
    // 工具箱背景颜色
    borderColor: '#ccc',
    // 工具箱边框颜色
    borderWidth: 0,
    // 工具箱边框线宽，单位px，默认为0（无边框）
    padding: 5,
    // 工具箱内边距，单位px，默认各方向内边距为5，
    // 接受数组分别设定上右下左边距，同css
    itemGap: 10,
    // 各个item之间的间隔，单位px，默认为10，
    // 横向布局时为水平间隔，纵向布局时为纵向间隔
    itemSize: 16,
    // 工具箱图形宽度
    showTitle: true,
    // textStyle: {},
    feature: {
        mark: {
            show: false,
            title: {
                mark: '辅助线开关',
                markUndo: '删除辅助线',
                markClear: '清空辅助线'
            },
            lineStyle: {
                width: 1,
                color: '#1e90ff',
                type: 'dashed'
            }
        },
        dataZoom: {
            show: false,
            title: {
                dataZoom: '区域缩放',
                dataZoomReset: '区域缩放后退'
            }
        },
        dataView: {
            show: false,
            title: '数据视图',
            readOnly: false,
            lang: [
                '数据视图',
                '关闭',
                '刷新'
            ]
        },
        magicType: {
            show: false,
            title: {
                line: '折线图切换',
                bar: '柱形图切换',
                stack: '堆积',
                tiled: '平铺',
                force: '力导向布局图切换',
                chord: '和弦图切换',
                pie: '饼图切换',
                funnel: '漏斗图切换'
            },
            /*
                option: {
                    line: {},
                    bar: {},
                    stack: {},
                    tiled: {},
                    force: {},
                    chord: {},
                    pie: {},
                    funnel: {}
                },
                */
            type: []    // 'line', 'bar', 'stack', 'tiled', 'force', 'chord', 'pie', 'funnel'
        },
        restore: {
            show: false,
            title: '还原'
        },
        saveAsImage: {
            show: false,
            title: '保存为图片',
            type: 'png',
            lang: ['点击保存']
        }
    }
};
var zrUtil = require('zrender/tool/util');
var zrConfig = require('zrender/config');
var zrEvent = require('zrender/tool/event');
var _MAGICTYPE_STACK = 'stack';
var _MAGICTYPE_TILED = 'tiled';
/**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {HtmlElement} dom 目标对象
     * @param {ECharts} myChart 当前图表实例
     */
function Toolbox(ecTheme, messageCenter, zr, option, myChart) {
    Base.call(this, ecTheme, messageCenter, zr, option, myChart);
    this.dom = myChart.dom;
    this._magicType = {};
    this._magicMap = {};
    this._isSilence = false;
    this._iconList;
    this._iconShapeMap = {};
    //this._itemGroupLocation;
    this._featureTitle = {};
    // 文字
    this._featureIcon = {};
    // 图标
    this._featureColor = {};
    // 颜色
    this._featureOption = {};
    this._enableColor = 'red';
    this._disableColor = '#ccc';
    // this._markStart;
    // this._marking;
    // this._markShape;
    // this._zoomStart;
    // this._zooming;
    // this._zoomShape;
    // this._zoomQueue;
    // this._dataView;
    this._markShapeList = [];
    var self = this;
    self._onMark = function (param) {
        self.__onMark(param);
    };
    self._onMarkUndo = function (param) {
        self.__onMarkUndo(param);
    };
    self._onMarkClear = function (param) {
        self.__onMarkClear(param);
    };
    self._onDataZoom = function (param) {
        self.__onDataZoom(param);
    };
    self._onDataZoomReset = function (param) {
        self.__onDataZoomReset(param);
    };
    self._onDataView = function (param) {
        self.__onDataView(param);
    };
    self._onRestore = function (param) {
        self.__onRestore(param);
    };
    self._onSaveAsImage = function (param) {
        self.__onSaveAsImage(param);
    };
    self._onMagicType = function (param) {
        self.__onMagicType(param);
    };
    self._onCustomHandler = function (param) {
        self.__onCustomHandler(param);
    };
    self._onmousemove = function (param) {
        return self.__onmousemove(param);
    };
    self._onmousedown = function (param) {
        return self.__onmousedown(param);
    };
    self._onmouseup = function (param) {
        return self.__onmouseup(param);
    };
    self._onclick = function (param) {
        return self.__onclick(param);
    };
}
Toolbox.prototype = {
    type: ecConfig.COMPONENT_TYPE_TOOLBOX,
    _buildShape: function () {
        this._iconList = [];
        var toolboxOption = this.option.toolbox;
        this._enableColor = toolboxOption.effectiveColor;
        this._disableColor = toolboxOption.disableColor;
        var feature = toolboxOption.feature;
        var iconName = [];
        for (var key in feature) {
            if (feature[key].show) {
                switch (key) {
                case 'mark':
                    iconName.push({
                        key: key,
                        name: 'mark'
                    });
                    iconName.push({
                        key: key,
                        name: 'markUndo'
                    });
                    iconName.push({
                        key: key,
                        name: 'markClear'
                    });
                    break;
                case 'magicType':
                    for (var i = 0, l = feature[key].type.length; i < l; i++) {
                        feature[key].title[feature[key].type[i] + 'Chart'] = feature[key].title[feature[key].type[i]];
                        if (feature[key].option) {
                            feature[key].option[feature[key].type[i] + 'Chart'] = feature[key].option[feature[key].type[i]];
                        }
                        iconName.push({
                            key: key,
                            name: feature[key].type[i] + 'Chart'
                        });
                    }
                    break;
                case 'dataZoom':
                    iconName.push({
                        key: key,
                        name: 'dataZoom'
                    });
                    iconName.push({
                        key: key,
                        name: 'dataZoomReset'
                    });
                    break;
                case 'saveAsImage':
                    if (this.canvasSupported) {
                        iconName.push({
                            key: key,
                            name: 'saveAsImage'
                        });
                    }
                    break;
                default:
                    iconName.push({
                        key: key,
                        name: key
                    });
                    break;
                }
            }
        }
        if (iconName.length > 0) {
            var name;
            var key;
            for (var i = 0, l = iconName.length; i < l; i++) {
                name = iconName[i].name;
                key = iconName[i].key;
                this._iconList.push(name);
                this._featureTitle[name] = feature[key].title[name] || feature[key].title;
                if (feature[key].icon) {
                    this._featureIcon[name] = feature[key].icon[name] || feature[key].icon;
                }
                if (feature[key].color) {
                    this._featureColor[name] = feature[key].color[name] || feature[key].color;
                }
                if (feature[key].option) {
                    this._featureOption[name] = feature[key].option[name] || feature[key].option;
                }
            }
            this._itemGroupLocation = this._getItemGroupLocation();
            this._buildBackground();
            this._buildItem();
            for (var i = 0, l = this.shapeList.length; i < l; i++) {
                this.zr.addShape(this.shapeList[i]);
            }
            if (this._iconShapeMap['mark']) {
                this._iconDisable(this._iconShapeMap['markUndo']);
                this._iconDisable(this._iconShapeMap['markClear']);
            }
            if (this._iconShapeMap['dataZoomReset'] && this._zoomQueue.length === 0) {
                this._iconDisable(this._iconShapeMap['dataZoomReset']);
            }
        }
    },
    /**
         * 构建所有图例元素
         */
    _buildItem: function () {
        var toolboxOption = this.option.toolbox;
        var iconLength = this._iconList.length;
        var lastX = this._itemGroupLocation.x;
        var lastY = this._itemGroupLocation.y;
        var itemSize = toolboxOption.itemSize;
        var itemGap = toolboxOption.itemGap;
        var itemShape;
        var color = toolboxOption.color instanceof Array ? toolboxOption.color : [toolboxOption.color];
        var textFont = this.getFont(toolboxOption.textStyle);
        var textPosition;
        var textAlign;
        var textBaseline;
        if (toolboxOption.orient === 'horizontal') {
            textPosition = this._itemGroupLocation.y / this.zr.getHeight() < 0.5 ? 'bottom' : 'top';
            textAlign = this._itemGroupLocation.x / this.zr.getWidth() < 0.5 ? 'left' : 'right';
            textBaseline = this._itemGroupLocation.y / this.zr.getHeight() < 0.5 ? 'top' : 'bottom';
        } else {
            textPosition = this._itemGroupLocation.x / this.zr.getWidth() < 0.5 ? 'right' : 'left';
        }
        this._iconShapeMap = {};
        var self = this;
        for (var i = 0; i < iconLength; i++) {
            // 图形
            itemShape = {
                type: 'icon',
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
                style: {
                    x: lastX,
                    y: lastY,
                    width: itemSize,
                    height: itemSize,
                    iconType: this._iconList[i],
                    lineWidth: 1,
                    strokeColor: this._featureColor[this._iconList[i]] || color[i % color.length],
                    brushType: 'stroke'
                },
                highlightStyle: {
                    lineWidth: 1,
                    text: toolboxOption.showTitle ? this._featureTitle[this._iconList[i]] : undefined,
                    textFont: textFont,
                    textPosition: textPosition,
                    strokeColor: this._featureColor[this._iconList[i]] || color[i % color.length]
                },
                hoverable: true,
                clickable: true
            };
            if (this._featureIcon[this._iconList[i]]) {
                itemShape.style.image = this._featureIcon[this._iconList[i]].replace(new RegExp('^image:\\/\\/'), '');
                itemShape.style.opacity = 0.8;
                itemShape.highlightStyle.opacity = 1;
                itemShape.type = 'image';
            }
            if (toolboxOption.orient === 'horizontal') {
                // 修正左对齐第一个或右对齐最后一个
                if (i === 0 && textAlign === 'left') {
                    itemShape.highlightStyle.textPosition = 'specific';
                    itemShape.highlightStyle.textAlign = textAlign;
                    itemShape.highlightStyle.textBaseline = textBaseline;
                    itemShape.highlightStyle.textX = lastX;
                    itemShape.highlightStyle.textY = textBaseline === 'top' ? lastY + itemSize + 10 : lastY - 10;
                }
                if (i === iconLength - 1 && textAlign === 'right') {
                    itemShape.highlightStyle.textPosition = 'specific';
                    itemShape.highlightStyle.textAlign = textAlign;
                    itemShape.highlightStyle.textBaseline = textBaseline;
                    itemShape.highlightStyle.textX = lastX + itemSize;
                    itemShape.highlightStyle.textY = textBaseline === 'top' ? lastY + itemSize + 10 : lastY - 10;
                }
            }
            switch (this._iconList[i]) {
            case 'mark':
                itemShape.onclick = self._onMark;
                break;
            case 'markUndo':
                itemShape.onclick = self._onMarkUndo;
                break;
            case 'markClear':
                itemShape.onclick = self._onMarkClear;
                break;
            case 'dataZoom':
                itemShape.onclick = self._onDataZoom;
                break;
            case 'dataZoomReset':
                itemShape.onclick = self._onDataZoomReset;
                break;
            case 'dataView':
                if (!this._dataView) {
                    var DataView = require('./dataView');
                    this._dataView = new DataView(this.ecTheme, this.messageCenter, this.zr, this.option, this.myChart);
                }
                itemShape.onclick = self._onDataView;
                break;
            case 'restore':
                itemShape.onclick = self._onRestore;
                break;
            case 'saveAsImage':
                itemShape.onclick = self._onSaveAsImage;
                break;
            default:
                if (this._iconList[i].match('Chart')) {
                    itemShape._name = this._iconList[i].replace('Chart', '');
                    itemShape.onclick = self._onMagicType;
                } else {
                    itemShape.onclick = self._onCustomHandler;
                }
                break;
            }
            if (itemShape.type === 'icon') {
                itemShape = new IconShape(itemShape);
            } else if (itemShape.type === 'image') {
                itemShape = new ImageShape(itemShape);
            }
            this.shapeList.push(itemShape);
            this._iconShapeMap[this._iconList[i]] = itemShape;
            if (toolboxOption.orient === 'horizontal') {
                lastX += itemSize + itemGap;
            } else {
                lastY += itemSize + itemGap;
            }
        }
    },
    _buildBackground: function () {
        var toolboxOption = this.option.toolbox;
        var padding = this.reformCssArray(this.option.toolbox.padding);
        this.shapeList.push(new RectangleShape({
            zlevel: this.getZlevelBase(),
            z: this.getZBase(),
            hoverable: false,
            style: {
                x: this._itemGroupLocation.x - padding[3],
                y: this._itemGroupLocation.y - padding[0],
                width: this._itemGroupLocation.width + padding[3] + padding[1],
                height: this._itemGroupLocation.height + padding[0] + padding[2],
                brushType: toolboxOption.borderWidth === 0 ? 'fill' : 'both',
                color: toolboxOption.backgroundColor,
                strokeColor: toolboxOption.borderColor,
                lineWidth: toolboxOption.borderWidth
            }
        }));
    },
    /**
         * 根据选项计算图例实体的位置坐标
         */
    _getItemGroupLocation: function () {
        var toolboxOption = this.option.toolbox;
        var padding = this.reformCssArray(this.option.toolbox.padding);
        var iconLength = this._iconList.length;
        var itemGap = toolboxOption.itemGap;
        var itemSize = toolboxOption.itemSize;
        var totalWidth = 0;
        var totalHeight = 0;
        if (toolboxOption.orient === 'horizontal') {
            // 水平布局，计算总宽度，别忘减去最后一个的itemGap
            totalWidth = (itemSize + itemGap) * iconLength - itemGap;
            totalHeight = itemSize;
        } else {
            // 垂直布局，计算总高度
            totalHeight = (itemSize + itemGap) * iconLength - itemGap;
            totalWidth = itemSize;
        }
        var x;
        var zrWidth = this.zr.getWidth();
        switch (toolboxOption.x) {
        case 'center':
            x = Math.floor((zrWidth - totalWidth) / 2);
            break;
        case 'left':
            x = padding[3] + toolboxOption.borderWidth;
            break;
        case 'right':
            x = zrWidth - totalWidth - padding[1] - toolboxOption.borderWidth;
            break;
        default:
            x = toolboxOption.x - 0;
            x = isNaN(x) ? 0 : x;
            break;
        }
        var y;
        var zrHeight = this.zr.getHeight();
        switch (toolboxOption.y) {
        case 'top':
            y = padding[0] + toolboxOption.borderWidth;
            break;
        case 'bottom':
            y = zrHeight - totalHeight - padding[2] - toolboxOption.borderWidth;
            break;
        case 'center':
            y = Math.floor((zrHeight - totalHeight) / 2);
            break;
        default:
            y = toolboxOption.y - 0;
            y = isNaN(y) ? 0 : y;
            break;
        }
        return {
            x: x,
            y: y,
            width: totalWidth,
            height: totalHeight
        };
    },
    __onmousemove: function (param) {
        if (this._marking) {
            this._markShape.style.xEnd = zrEvent.getX(param.event);
            this._markShape.style.yEnd = zrEvent.getY(param.event);
            this.zr.addHoverShape(this._markShape);
        }
        if (this._zooming) {
            this._zoomShape.style.width = zrEvent.getX(param.event) - this._zoomShape.style.x;
            this._zoomShape.style.height = zrEvent.getY(param.event) - this._zoomShape.style.y;
            this.zr.addHoverShape(this._zoomShape);
            this.dom.style.cursor = 'crosshair';
            zrEvent.stop(param.event);
        }
        if (this._zoomStart && (this.dom.style.cursor != 'pointer' && this.dom.style.cursor != 'move')) {
            this.dom.style.cursor = 'crosshair';
        }
    },
    __onmousedown: function (param) {
        if (param.target) {
            return;
        }
        this._zooming = true;
        var x = zrEvent.getX(param.event);
        var y = zrEvent.getY(param.event);
        var zoomOption = this.option.dataZoom || {};
        this._zoomShape = new RectangleShape({
            zlevel: this.getZlevelBase(),
            z: this.getZBase(),
            style: {
                x: x,
                y: y,
                width: 1,
                height: 1,
                brushType: 'both'
            },
            highlightStyle: {
                lineWidth: 2,
                color: zoomOption.fillerColor || ecConfig.dataZoom.fillerColor,
                strokeColor: zoomOption.handleColor || ecConfig.dataZoom.handleColor,
                brushType: 'both'
            }
        });
        this.zr.addHoverShape(this._zoomShape);
        return true;    // 阻塞全局事件
    },
    __onmouseup: function () {
        if (!this._zoomShape || Math.abs(this._zoomShape.style.width) < 10 || Math.abs(this._zoomShape.style.height) < 10) {
            this._zooming = false;
            return true;
        }
        if (this._zooming && this.component.dataZoom) {
            this._zooming = false;
            var zoom = this.component.dataZoom.rectZoom(this._zoomShape.style);
            if (zoom) {
                this._zoomQueue.push({
                    start: zoom.start,
                    end: zoom.end,
                    start2: zoom.start2,
                    end2: zoom.end2
                });
                this._iconEnable(this._iconShapeMap['dataZoomReset']);
                this.zr.refreshNextFrame();
            }
        }
        return true;    // 阻塞全局事件
    },
    __onclick: function (param) {
        if (param.target) {
            return;
        }
        if (this._marking) {
            this._marking = false;
            this._markShapeList.push(this._markShape);
            this._iconEnable(this._iconShapeMap['markUndo']);
            this._iconEnable(this._iconShapeMap['markClear']);
            this.zr.addShape(this._markShape);
            this.zr.refreshNextFrame();
        } else if (this._markStart) {
            this._marking = true;
            var x = zrEvent.getX(param.event);
            var y = zrEvent.getY(param.event);
            this._markShape = new LineShape({
                zlevel: this.getZlevelBase(),
                z: this.getZBase(),
                style: {
                    xStart: x,
                    yStart: y,
                    xEnd: x,
                    yEnd: y,
                    lineWidth: this.query(this.option, 'toolbox.feature.mark.lineStyle.width'),
                    strokeColor: this.query(this.option, 'toolbox.feature.mark.lineStyle.color'),
                    lineType: this.query(this.option, 'toolbox.feature.mark.lineStyle.type')
                }
            });
            this.zr.addHoverShape(this._markShape);
        }
    },
    __onMark: function (param) {
        var target = param.target;
        if (this._marking || this._markStart) {
            // 取消
            this._resetMark();
            this.zr.refreshNextFrame();
        } else {
            // 启用Mark
            this._resetZoom();
            // mark与dataZoom互斥
            this.zr.modShape(target.id, { style: { strokeColor: this._enableColor } });
            this.zr.refreshNextFrame();
            this._markStart = true;
            var self = this;
            setTimeout(function () {
                self.zr && self.zr.on(zrConfig.EVENT.CLICK, self._onclick) && self.zr.on(zrConfig.EVENT.MOUSEMOVE, self._onmousemove);
            }, 10);
        }
        return true;    // 阻塞全局事件
    },
    __onMarkUndo: function () {
        if (this._marking) {
            this._marking = false;
        } else {
            var len = this._markShapeList.length;
            if (len >= 1) {
                var target = this._markShapeList[len - 1];
                this.zr.delShape(target.id);
                this.zr.refreshNextFrame();
                this._markShapeList.pop();
                if (len === 1) {
                    this._iconDisable(this._iconShapeMap['markUndo']);
                    this._iconDisable(this._iconShapeMap['markClear']);
                }
            }
        }
        return true;
    },
    __onMarkClear: function () {
        if (this._marking) {
            this._marking = false;
        }
        var len = this._markShapeList.length;
        if (len > 0) {
            while (len--) {
                this.zr.delShape(this._markShapeList.pop().id);
            }
            this._iconDisable(this._iconShapeMap['markUndo']);
            this._iconDisable(this._iconShapeMap['markClear']);
            this.zr.refreshNextFrame();
        }
        return true;
    },
    __onDataZoom: function (param) {
        var target = param.target;
        if (this._zooming || this._zoomStart) {
            // 取消
            this._resetZoom();
            this.zr.refreshNextFrame();
            this.dom.style.cursor = 'default';
        } else {
            // 启用Zoom
            this._resetMark();
            // mark与dataZoom互斥
            this.zr.modShape(target.id, { style: { strokeColor: this._enableColor } });
            this.zr.refreshNextFrame();
            this._zoomStart = true;
            var self = this;
            setTimeout(function () {
                self.zr && self.zr.on(zrConfig.EVENT.MOUSEDOWN, self._onmousedown) && self.zr.on(zrConfig.EVENT.MOUSEUP, self._onmouseup) && self.zr.on(zrConfig.EVENT.MOUSEMOVE, self._onmousemove);
            }, 10);
            this.dom.style.cursor = 'crosshair';
        }
        return true;    // 阻塞全局事件
    },
    __onDataZoomReset: function () {
        if (this._zooming) {
            this._zooming = false;
        }
        this._zoomQueue.pop();
        //console.log(this._zoomQueue)
        if (this._zoomQueue.length > 0) {
            this.component.dataZoom.absoluteZoom(this._zoomQueue[this._zoomQueue.length - 1]);
        } else {
            this.component.dataZoom.rectZoom();
            this._iconDisable(this._iconShapeMap['dataZoomReset']);
            this.zr.refreshNextFrame();
        }
        return true;
    },
    _resetMark: function () {
        this._marking = false;
        if (this._markStart) {
            this._markStart = false;
            if (this._iconShapeMap['mark']) {
                // 还原图标为未生效状态
                this.zr.modShape(this._iconShapeMap['mark'].id, { style: { strokeColor: this._iconShapeMap['mark'].highlightStyle.strokeColor } });
            }
            this.zr.un(zrConfig.EVENT.CLICK, this._onclick);
            this.zr.un(zrConfig.EVENT.MOUSEMOVE, this._onmousemove);
        }
    },
    _resetZoom: function () {
        this._zooming = false;
        if (this._zoomStart) {
            this._zoomStart = false;
            if (this._iconShapeMap['dataZoom']) {
                // 还原图标为未生效状态
                this.zr.modShape(this._iconShapeMap['dataZoom'].id, { style: { strokeColor: this._iconShapeMap['dataZoom'].highlightStyle.strokeColor } });
            }
            this.zr.un(zrConfig.EVENT.MOUSEDOWN, this._onmousedown);
            this.zr.un(zrConfig.EVENT.MOUSEUP, this._onmouseup);
            this.zr.un(zrConfig.EVENT.MOUSEMOVE, this._onmousemove);
        }
    },
    _iconDisable: function (target) {
        if (target.type != 'image') {
            this.zr.modShape(target.id, {
                hoverable: false,
                clickable: false,
                style: { strokeColor: this._disableColor }
            });
        } else {
            this.zr.modShape(target.id, {
                hoverable: false,
                clickable: false,
                style: { opacity: 0.3 }
            });
        }
    },
    _iconEnable: function (target) {
        if (target.type != 'image') {
            this.zr.modShape(target.id, {
                hoverable: true,
                clickable: true,
                style: { strokeColor: target.highlightStyle.strokeColor }
            });
        } else {
            this.zr.modShape(target.id, {
                hoverable: true,
                clickable: true,
                style: { opacity: 0.8 }
            });
        }
    },
    __onDataView: function () {
        this._dataView.show(this.option);
        return true;
    },
    __onRestore: function () {
        this._resetMark();
        this._resetZoom();
        this.messageCenter.dispatch(ecConfig.EVENT.RESTORE, null, null, this.myChart);
        return true;
    },
    __onSaveAsImage: function () {
        var saveOption = this.option.toolbox.feature.saveAsImage;
        var imgType = saveOption.type || 'png';
        if (imgType != 'png' && imgType != 'jpeg') {
            imgType = 'png';
        }
        var image;
        if (!this.myChart.isConnected()) {
            image = this.zr.toDataURL('image/' + imgType, this.option.backgroundColor && this.option.backgroundColor.replace(' ', '') === 'rgba(0,0,0,0)' ? '#fff' : this.option.backgroundColor);
        } else {
            image = this.myChart.getConnectedDataURL(imgType);
        }
        var downloadDiv = document.createElement('div');
        downloadDiv.id = '__echarts_download_wrap__';
        downloadDiv.style.cssText = 'position:fixed;' + 'z-index:99999;' + 'display:block;' + 'top:0;left:0;' + 'background-color:rgba(33,33,33,0.5);' + 'text-align:center;' + 'width:100%;' + 'height:100%;' + 'line-height:' + document.documentElement.clientHeight + 'px;';
        var downloadLink = document.createElement('a');
        //downloadLink.onclick = _saveImageForIE;
        downloadLink.href = image;
        downloadLink.setAttribute('download', (saveOption.name ? saveOption.name : this.option.title && (this.option.title.text || this.option.title.subtext) ? this.option.title.text || this.option.title.subtext : 'ECharts') + '.' + imgType);
        downloadLink.innerHTML = '<img style="vertical-align:middle" src="' + image + '" title="' + (!!window.ActiveXObject || 'ActiveXObject' in window ? '右键->图片另存为' : saveOption.lang ? saveOption.lang[0] : '点击保存') + '"/>';
        downloadDiv.appendChild(downloadLink);
        document.body.appendChild(downloadDiv);
        downloadLink = null;
        downloadDiv = null;
        setTimeout(function () {
            var _d = document.getElementById('__echarts_download_wrap__');
            if (_d) {
                _d.onclick = function () {
                    var d = document.getElementById('__echarts_download_wrap__');
                    d.onclick = null;
                    d.innerHTML = '';
                    document.body.removeChild(d);
                    d = null;
                };
                _d = null;
            }
        }, 500);
        /*
            function _saveImageForIE() {
                window.win = window.open(image);
                win.document.execCommand("SaveAs");
                win.close()
            }
            */
        return;
    },
    __onMagicType: function (param) {
        this._resetMark();
        var itemName = param.target._name;
        if (!this._magicType[itemName]) {
            // 启用
            this._magicType[itemName] = true;
            // 折柱互斥
            if (itemName === ecConfig.CHART_TYPE_LINE) {
                this._magicType[ecConfig.CHART_TYPE_BAR] = false;
            } else if (itemName === ecConfig.CHART_TYPE_BAR) {
                this._magicType[ecConfig.CHART_TYPE_LINE] = false;
            }
            // 饼图漏斗互斥
            if (itemName === ecConfig.CHART_TYPE_PIE) {
                this._magicType[ecConfig.CHART_TYPE_FUNNEL] = false;
            } else if (itemName === ecConfig.CHART_TYPE_FUNNEL) {
                this._magicType[ecConfig.CHART_TYPE_PIE] = false;
            }
            // 力导和弦互斥
            if (itemName === ecConfig.CHART_TYPE_FORCE) {
                this._magicType[ecConfig.CHART_TYPE_CHORD] = false;
            } else if (itemName === ecConfig.CHART_TYPE_CHORD) {
                this._magicType[ecConfig.CHART_TYPE_FORCE] = false;
            }
            // 堆积平铺互斥
            if (itemName === _MAGICTYPE_STACK) {
                this._magicType[_MAGICTYPE_TILED] = false;
            } else if (itemName === _MAGICTYPE_TILED) {
                this._magicType[_MAGICTYPE_STACK] = false;
            }
            this.messageCenter.dispatch(ecConfig.EVENT.MAGIC_TYPE_CHANGED, param.event, { magicType: this._magicType }, this.myChart);
        }
        return true;
    },
    setMagicType: function (magicType) {
        this._resetMark();
        this._magicType = magicType;
        !this._isSilence && this.messageCenter.dispatch(ecConfig.EVENT.MAGIC_TYPE_CHANGED, null, { magicType: this._magicType }, this.myChart);
    },
    // 用户自定义扩展toolbox方法
    __onCustomHandler: function (param) {
        var target = param.target.style.iconType;
        var featureHandler = this.option.toolbox.feature[target].onclick;
        if (typeof featureHandler === 'function') {
            featureHandler.call(this, this.option);
        }
    },
    // 重置备份还原状态等
    reset: function (newOption, isRestore) {
        isRestore && this.clear();
        if (this.query(newOption, 'toolbox.show') && this.query(newOption, 'toolbox.feature.magicType.show')) {
            var magicType = newOption.toolbox.feature.magicType.type;
            var len = magicType.length;
            this._magicMap = {};
            // 标识可控类型
            while (len--) {
                this._magicMap[magicType[len]] = true;
            }
            len = newOption.series.length;
            var oriType;
            // 备份还原可控类型
            var axis;
            while (len--) {
                oriType = newOption.series[len].type;
                if (this._magicMap[oriType]) {
                    axis = newOption.xAxis instanceof Array ? newOption.xAxis[newOption.series[len].xAxisIndex || 0] : newOption.xAxis;
                    if (axis && (axis.type || 'category') === 'category') {
                        axis.__boundaryGap = axis.boundaryGap != null ? axis.boundaryGap : true;
                    }
                    axis = newOption.yAxis instanceof Array ? newOption.yAxis[newOption.series[len].yAxisIndex || 0] : newOption.yAxis;
                    if (axis && axis.type === 'category') {
                        axis.__boundaryGap = axis.boundaryGap != null ? axis.boundaryGap : true;
                    }
                    newOption.series[len].__type = oriType;
                    // 避免不同类型图表类型的样式污染
                    newOption.series[len].__itemStyle = zrUtil.clone(newOption.series[len].itemStyle || {});
                }
                if (this._magicMap[_MAGICTYPE_STACK] || this._magicMap[_MAGICTYPE_TILED]) {
                    newOption.series[len].__stack = newOption.series[len].stack;
                }
            }
        }
        this._magicType = isRestore ? {} : this._magicType || {};
        for (var itemName in this._magicType) {
            if (this._magicType[itemName]) {
                this.option = newOption;
                this.getMagicOption();
                break;
            }
        }
        // 框选缩放
        var zoomOption = newOption.dataZoom;
        if (zoomOption && zoomOption.show) {
            var start = zoomOption.start != null && zoomOption.start >= 0 && zoomOption.start <= 100 ? zoomOption.start : 0;
            var end = zoomOption.end != null && zoomOption.end >= 0 && zoomOption.end <= 100 ? zoomOption.end : 100;
            if (start > end) {
                // 大小颠倒自动翻转
                start = start + end;
                end = start - end;
                start = start - end;
            }
            this._zoomQueue = [{
                    start: start,
                    end: end,
                    start2: 0,
                    end2: 100
                }];
        } else {
            this._zoomQueue = [];
        }
    },
    getMagicOption: function () {
        var axis;
        var chartType;
        if (this._magicType[ecConfig.CHART_TYPE_LINE] || this._magicType[ecConfig.CHART_TYPE_BAR]) {
            // 图表类型有折柱切换
            var boundaryGap = this._magicType[ecConfig.CHART_TYPE_LINE] ? false : true;
            for (var i = 0, l = this.option.series.length; i < l; i++) {
                chartType = this.option.series[i].type;
                if (chartType == ecConfig.CHART_TYPE_LINE || chartType == ecConfig.CHART_TYPE_BAR) {
                    axis = this.option.xAxis instanceof Array ? this.option.xAxis[this.option.series[i].xAxisIndex || 0] : this.option.xAxis;
                    if (axis && (axis.type || 'category') === 'category') {
                        axis.boundaryGap = boundaryGap ? true : axis.__boundaryGap;
                    }
                    axis = this.option.yAxis instanceof Array ? this.option.yAxis[this.option.series[i].yAxisIndex || 0] : this.option.yAxis;
                    if (axis && axis.type === 'category') {
                        axis.boundaryGap = boundaryGap ? true : axis.__boundaryGap;
                    }
                }
            }
            this._defaultMagic(ecConfig.CHART_TYPE_LINE, ecConfig.CHART_TYPE_BAR);
        }
        this._defaultMagic(ecConfig.CHART_TYPE_CHORD, ecConfig.CHART_TYPE_FORCE);
        this._defaultMagic(ecConfig.CHART_TYPE_PIE, ecConfig.CHART_TYPE_FUNNEL);
        if (this._magicType[_MAGICTYPE_STACK] || this._magicType[_MAGICTYPE_TILED]) {
            // 有堆积平铺切换
            for (var i = 0, l = this.option.series.length; i < l; i++) {
                if (this._magicType[_MAGICTYPE_STACK]) {
                    // 启用堆积
                    this.option.series[i].stack = '_ECHARTS_STACK_KENER_2014_';
                    chartType = _MAGICTYPE_STACK;
                } else if (this._magicType[_MAGICTYPE_TILED]) {
                    // 启用平铺
                    this.option.series[i].stack = null;
                    chartType = _MAGICTYPE_TILED;
                }
                if (this._featureOption[chartType + 'Chart']) {
                    zrUtil.merge(this.option.series[i], this._featureOption[chartType + 'Chart'] || {}, true);
                }
            }
        }
        return this.option;
    },
    _defaultMagic: function (cType1, cType2) {
        if (this._magicType[cType1] || this._magicType[cType2]) {
            for (var i = 0, l = this.option.series.length; i < l; i++) {
                var chartType = this.option.series[i].type;
                if (chartType == cType1 || chartType == cType2) {
                    this.option.series[i].type = this._magicType[cType1] ? cType1 : cType2;
                    // 避免不同类型图表类型的样式污染
                    this.option.series[i].itemStyle = zrUtil.clone(this.option.series[i].__itemStyle);
                    chartType = this.option.series[i].type;
                    if (this._featureOption[chartType + 'Chart']) {
                        zrUtil.merge(this.option.series[i], this._featureOption[chartType + 'Chart'] || {}, true);
                    }
                }
            }
        }
    },
    silence: function (s) {
        this._isSilence = s;
    },
    resize: function () {
        this._resetMark();
        this.clear();
        if (this.option && this.option.toolbox && this.option.toolbox.show) {
            this._buildShape();
        }
        if (this._dataView) {
            this._dataView.resize();
        }
    },
    hideDataView: function () {
        if (this._dataView) {
            this._dataView.hide();
        }
    },
    clear: function (notMark) {
        if (this.zr) {
            this.zr.delShape(this.shapeList);
            this.shapeList = [];
            if (!notMark) {
                this.zr.delShape(this._markShapeList);
                this._markShapeList = [];
            }
        }
    },
    /**
         * 释放后实例不可用
         */
    onbeforDispose: function () {
        if (this._dataView) {
            this._dataView.dispose();
            this._dataView = null;
        }
        this._markShapeList = null;
    },
    /**
         * 刷新
         */
    refresh: function (newOption) {
        if (newOption) {
            this._resetMark();
            this._resetZoom();
            newOption.toolbox = this.reformOption(newOption.toolbox);
            this.option = newOption;
            this.clear(true);
            if (newOption.toolbox.show) {
                this._buildShape();
            }
            this.hideDataView();
        }
    }
};
zrUtil.inherits(Toolbox, Base);
require('../component').define('toolbox', Toolbox);
module.exports = Toolbox || module.exports;;